<template>
  <div class="uploadImg"  v-loading="uploading" element-loading-text="图片上传中..." @paste="handlePaste">
    <div class="input-container">
      <div class="img-box">
        <img src="../../assets/upload.svg" alt="">
        <br/>
        <span>
          点击选择上传的图片文件，或将图片文件拖拽到此处，<span style="color: red;">支持多文件上传</span>；
          <br>
          也可以复制图片或图片链接然后按Ctrl+V粘贴上传（在粘贴之前请使用鼠标点击一下右侧区域）
        </span>
      </div>
      <input type="file" ref="fileInput" accept="image/*" multiple >
    </div>
    <div class="preview">
      <div class="remain-info">
        剩余可上传数量:{{ remainNum }}
      </div>
      <div class="category-option">
        <span class="info">选择要上传到的相册：</span>
        <el-select v-model="selectValue" class="m-2" placeholder="Select" size="default">
          <el-option
            v-for="item in options"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </div>
      <img :src="previewUrl" alt="">
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from "@vue/reactivity";
import { ElMessage } from "element-plus";
import { computed, onMounted, Ref } from "vue";
import { getUploadToken, saveImage, uploadImageFile, uploadImageBase64, UploadResult, uploadImageUrl } from "../../request/img";
import { useImageStore } from "../../store/image";
import { useUserStore } from "../../store/user";
const fileInput = ref<HTMLInputElement>() as Ref<HTMLInputElement>
const previewUrl = ref('')
const uploading = ref(false)
const imageStore = useImageStore()
const userStore = useUserStore()
const remainNum = computed(() => ((userStore.user.maxNumber as number) - (userStore.user.number as number)) )
const selectValue = ref('')
const categoryId = computed(() => {
  if(selectValue.value == ''){
    return 0
  }
  return parseInt(selectValue.value)
})
const options = computed(() => {
  let optionArr = [] as any[]
  imageStore.categories.forEach(val => {
    optionArr.push({label: val.categoryName, value: val.id.toString()})
  })
  return optionArr
})
async function upload(image:File|string, method:'url'|'base64'|'file'){
  let uploadToken = (await getUploadToken()).data
  let uploadResult = {} as UploadResult
  if(method === 'file'){
    uploadResult = (await uploadImageFile(image as File, uploadToken)).data
  }
  else if(method === 'base64'){
    uploadResult = (await uploadImageBase64(image as string, uploadToken)).data
  }
  else if(method === 'url'){
    uploadResult = (await uploadImageUrl(image as string, uploadToken)).data
  }
  if(uploadResult.err){
    ElMessage({type:'error', message:'图片上传失败，请稍后再试'})
    return Promise.reject("")
  }
  let saveResult = (await saveImage(uploadResult.url as string, uploadResult.id as string, categoryId.value)).data
  return saveResult
}
// 在doUpload里修改loading
function doUpload(image:File|string, method:'url'|'base64'|'file'){
  if(remainNum.value <= 0){
    ElMessage({type:'error', message:'对不起，你的剩余可上传数量为0'})
    return
  }
  uploading.value = true
  upload(image, method).then(
    val => {
      // 上传成功，val为后端返回的image对象
      previewUrl.value = val.url
      uploading.value = false
      imageStore.addImage(val)
      userStore.user.number = userStore.user.number as number + 1
      ElMessage({type: 'success', message: '上传成功'})
    },
    error => {
      uploading.value = false
    }
  )
}
// 上传多个文件类型的图片
async function doMultipleFileUpload(images:FileList){
  if(remainNum.value < images.length){
    ElMessage({type:'error', message:'对不起，你的剩余可上传数量不足'})
    return
  }
  uploading.value = true
  for(let i = 0; i < images.length; i++){
    try{
      let result = await upload(images[i], 'file')
      imageStore.addImage(result)
      userStore.user.number = userStore.user.number as number + 1
      if(i == images.length - 1){
        previewUrl.value = result.url
      }
    }
    catch{
      ElMessage({type: 'error', message: `第${i + 1}张图片上传出错！`})
    }
    finally{
      if((i + 1) % 3 == 0){
        ElMessage({type: 'success', message: `已上传${i + 1}张图片`})
      }
    }
  }
  ElMessage({type: 'success', message: `所有图片上传完毕`})
  uploading.value = false
}
function handlePaste(e:ClipboardEvent){

  if(/image\/.+/.test(e.clipboardData?.items[0].type || '')){
    let file = e.clipboardData?.items[0].getAsFile() as File
    doUpload(file, 'file')
  }
  else if(/text\/.+/.test(e.clipboardData?.items[0].type || '')){
    // 必须先把type存起来，因为getAsString之后就访问不到e.clipboardData?.items[0]对象了
    let type = e.clipboardData?.items[0].type 
    let isImage = false
    e.clipboardData?.items[0].getAsString(pasteStr => {
      let url = ''
      // 如果是纯字符串
      if(type === 'text/plain'){
        if(/https?:\/\//.test(pasteStr) || /data:image.+/.test(pasteStr)){
          url = pasteStr
          isImage = true
        }
      }
      // 如果是xml或html文本字符串
      else {
        let results = pasteStr.match(/src=".+?"/)
        if(results){
          url = results[0].slice(5, results[0].length - 1) // url就是标签里src属性的值
          isImage = true
        }
      }
      // 如果url不为空，说明提取到了链接，判断是http还是base64链接
      if(url){
        if(/data:image.+/.test(url)){ // 如果url是base64编码的值
          doUpload(url, 'base64')
          return
        }
        else{
          doUpload(url, 'url')
        }
      }
      if(!isImage){
        ElMessage({type:'warning', message: '请粘贴图片或图片链接！'})
      }
    })

  }
  else{
    ElMessage({type:'warning', message: '请粘贴图片或图片链接！'})
  }
}
// 挂载后，才能访问到ref属性绑定的dom对象
onMounted(() => {
  fileInput.value.onchange = () => {
    if(fileInput.value.files?.length == 1){
      doUpload(fileInput.value.files[0], 'file')
    }
    else if(fileInput.value.files?.length as number > 1){
      doMultipleFileUpload(fileInput.value.files as FileList)
    }
  }
})

</script>

<style scoped>

</style>